/*
 * eID Test PKI Project.
 * Copyright (C) 2012 FedICT.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License version
 * 3.0 as published by the Free Software Foundation.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, see 
 * http://www.gnu.org/licenses/.
 */

package be.fedict.eid.pki.model;

import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Date;

import javax.annotation.Resource;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.ejb.Timeout;
import javax.ejb.Timer;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.joda.time.DateTime;

import be.fedict.eid.pki.entity.CertificateAuthorityEntity;
import be.fedict.eid.pki.exception.InvalidPolicyException;
import be.fedict.eid.pki.exception.InvalidX500NameException;

@Stateless
public class IntermediateCAManagerBean {

	private static final Log LOG = LogFactory
			.getLog(IntermediateCAManagerBean.class);

	@Resource
	private TimerService timerService;

	@PersistenceContext
	private EntityManager entityManager;

	@EJB
	private PKIGeneratorBean pkiGeneratorBean;

	public void init(CertificateAuthorityEntity rootCertificateAuthorityEntity) {
		LOG.debug("init");
		String caName = rootCertificateAuthorityEntity.getName();
		TimerConfig timerConfig = new TimerConfig(caName, false);
		this.timerService.createSingleActionTimer(new Date(), timerConfig);
	}

	@Timeout
	private void timeout(Timer timer) {
		LOG.debug("timeout");
		String caName = (String) timer.getInfo();
		LOG.debug("CA name: " + caName);
		CertificateAuthorityEntity certificateAuthorityEntity = this.entityManager
				.find(CertificateAuthorityEntity.class, caName);
		int spawnCount = certificateAuthorityEntity.getInterSpawnCount();
		LOG.debug("spawn count: " + spawnCount);
		int interCount = certificateAuthorityEntity.getInterCount();
		int keySize = certificateAuthorityEntity.getKeySize();
		X509Certificate rootCACertificate = certificateAuthorityEntity
				.getCertificate();
		String interPolicyOid = certificateAuthorityEntity.getInterPolicyOid();
		LOG.debug("inter policy OID: " + interPolicyOid);
		PrivateKey rootPrivateKey = certificateAuthorityEntity.getPrivateKey();
		int interval = interCount / spawnCount;
		LOG.debug("interval: " + interval);
		DateTime notBefore = new DateTime(
				certificateAuthorityEntity.getNotBefore()).plusMinutes(interval
				* certificateAuthorityEntity.getInterSpawnInterval());
		DateTime notAfter = notBefore.plusMinutes(certificateAuthorityEntity
				.getInterValidity());
		if (notAfter.isAfter(new DateTime(certificateAuthorityEntity
				.getNotAfter()))) {
			LOG.debug("will not generate anymore intermediate CAs");
			return;
		}
		LOG.debug("notBefore : " + notBefore);
		LOG.debug("notAfter: " + notAfter);
		while (spawnCount > 0) {
			interCount++;
			String interCaName = caName + "-" + interCount;
			LOG.debug("intermediate CA name: " + interCaName);
			KeyPair interKeyPair = this.pkiGeneratorBean
					.generateKeyPair(keySize);
			// TODO: crlUrl should receive some value for localhost:8080
			String crlUrl = "http://localhost:8080/crls" + interCaName + ".crl";
			String subjectName = certificateAuthorityEntity.getInterSubject()
					+ ", SERIALNUMBER=" + interCount;
			try {
				this.pkiGeneratorBean.generateIntermediateCACertificate(
						rootCACertificate, notBefore, notAfter, subjectName,
						interKeyPair.getPublic(), interPolicyOid,
						rootPrivateKey, crlUrl);
			} catch (InvalidX500NameException e) {
				throw new RuntimeException(e);
			} catch (InvalidPolicyException e) {
				throw new RuntimeException(e);
			}
			spawnCount--;
		}
		certificateAuthorityEntity.setInterCount(interCount);
		TimerConfig timerConfig = new TimerConfig(caName, false);
		this.timerService.createSingleActionTimer(
				notBefore.plusMinutes(
						certificateAuthorityEntity.getInterSpawnInterval())
						.toDate(), timerConfig);
	}

	public void remove(CertificateAuthorityEntity certificateAuthorityEntity) {
		for (Timer timer : this.timerService.getTimers()) {
			String caName = (String) timer.getInfo();
			if (caName.equals(certificateAuthorityEntity.getName())) {
				timer.cancel();
			}
		}
		// TODO: remove all intermediate CA's under the root CA.
	}
}
